package com.voice.call.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.CodingErrorAction;
import java.util.Arrays;
import java.util.Properties;

import javax.net.ssl.SSLContext;

import org.apache.http.Consts;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.MessageConstraints;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

/**
 * HttpClient连接管理器
 * 
 * @author qugf
 */
public final class HttpClientConnectionManager {
	
	private static Logger LOG = LoggerFactory.getLogger(HttpClientConnectionManager.class);
	private static PoolingHttpClientConnectionManager connManager = null;
	private static CloseableHttpClient httpClient = null;
	// 客户端连接到url的连接超时时间（毫秒）
	private static int HTTP_CONNECTION_TIMEOUT = 3000;
	// 读取数据超时时间（毫秒），既两个连续的数据包之间的最长不活动时间
	private static int HTTP_SOCKET_TIMEOUT = 3000;
	// 从连接管理器获取连接的超时时间
	private static int HTTP_CONNECTION_REQUEST_TIMEOUTT = 1000;
	// 连接总数
	private static int HTTP_MAX_TOTAL_CONNECTIONS = 80;
	// 每个主机的最大的连接数
	private static int HTTP_MAX_CONNECTIONS_PER_HOST = 50;
	
	private static final String DEFAULT_CONFIG = "config-integrate.properties";
	private static final Properties props = new Properties();
	
	static {
		try {
			//初始化参数配置
			initProfile();
			
			// 创建基于系统的SSL上下文安全
			SSLContext sslcontext = SSLContexts.createSystemDefault();
			// 注册Socket连接工厂
			Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
					.register("http", PlainConnectionSocketFactory.INSTANCE)
					.register("https", new SSLConnectionSocketFactory(sslcontext))
					.build();
			// 创建连接池管理器
			connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

			// 创建套接字配置项
			SocketConfig socketConfig = SocketConfig.custom()
					.setTcpNoDelay(true)
					.setSoReuseAddress(true)
					.setSoTimeout(HTTP_SOCKET_TIMEOUT)
					.build();

			connManager.setDefaultSocketConfig(socketConfig);

			//创建消息约束
			MessageConstraints messageConstraints = MessageConstraints.custom()
					.setMaxHeaderCount(200)
					.setMaxLineLength(2000)
					.build();
			
			// 创建连接配置
			ConnectionConfig connectionConfig = ConnectionConfig.custom()
					.setMalformedInputAction(CodingErrorAction.IGNORE)
					.setUnmappableInputAction(CodingErrorAction.IGNORE)
					.setCharset(Consts.UTF_8)
					.setMessageConstraints(messageConstraints)
					.build();

			connManager.setDefaultConnectionConfig(connectionConfig);
			connManager.setMaxTotal(HTTP_MAX_TOTAL_CONNECTIONS);
			connManager.setDefaultMaxPerRoute(HTTP_MAX_CONNECTIONS_PER_HOST);
			
			// 使用cookie
	        CookieStore cookieStore = new BasicCookieStore();
	        // 使用用户凭证
	        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
	        // 创建全局请求配置对象
	        RequestConfig defaultRequestConfig = RequestConfig.custom()
	            .setCookieSpec(CookieSpecs.DEFAULT)
	            .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
	            .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
	            .setExpectContinueEnabled(false)
	            .setConnectTimeout(HTTP_CONNECTION_TIMEOUT)
	            .setSocketTimeout(HTTP_SOCKET_TIMEOUT)
	            .setConnectionRequestTimeout(HTTP_CONNECTION_REQUEST_TIMEOUTT)
	            .build();
			
	        // 创建httpClient
	        httpClient = HttpClients.custom()
		            .setConnectionManager(connManager)
		            .setDefaultCookieStore(cookieStore)
		            .setDefaultCredentialsProvider(credentialsProvider)
		            .setDefaultRequestConfig(defaultRequestConfig)
		            .build();
		} catch (Exception e) {
			LOG.warn(e.getMessage());
		} 
	}
	
	static void initProfile() {
		InputStream in = null;
		try {
			in = HttpClientConnectionManager.class.getClassLoader().getResourceAsStream(DEFAULT_CONFIG);
			props.load(new InputStreamReader(in, Consts.UTF_8));
		} catch (Exception e) {
			LOG.warn("config-file[{}] loaded failure !", DEFAULT_CONFIG);
			return;
		} finally {
			if (in != null) {
				try {
					in.close();
					in = null;
				} catch (IOException e) {
					// do nothing
				}
			}
		}
		
		String conn_timeout = props.getProperty("http.connection.timeout", HTTP_CONNECTION_TIMEOUT+"");
		String so_timeout = props.getProperty("http.so.timeout", HTTP_SOCKET_TIMEOUT+"");
		String conn_req_timeout = props.getProperty("http.connection.resquest.timeout", HTTP_CONNECTION_REQUEST_TIMEOUTT+"");
		String max_total_connections = props.getProperty("http.max.total.connections", HTTP_MAX_TOTAL_CONNECTIONS+"");
		String max_connections_per_host = props.getProperty("http.default.max.connections.per.host", HTTP_MAX_CONNECTIONS_PER_HOST+"");
		
		HTTP_CONNECTION_TIMEOUT = Integer.parseInt(conn_timeout);
		HTTP_SOCKET_TIMEOUT = Integer.parseInt(so_timeout);
		HTTP_CONNECTION_REQUEST_TIMEOUTT = Integer.parseInt(conn_req_timeout);
		HTTP_MAX_TOTAL_CONNECTIONS = Integer.parseInt(max_total_connections);
		HTTP_MAX_CONNECTIONS_PER_HOST = Integer.parseInt(max_connections_per_host);
	}
	
	public static CloseableHttpClient getHttpClientInstance() {
		return HttpClientConnectionManager.httpClient;
	}
	
}
